package com.jxtc.enterprise.admin.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jxtc.enterprise.admin.dto.*;
import com.jxtc.enterprise.admin.service.AdminTenantManageService;
import com.jxtc.enterprise.admin.service.AdminTenantStoreService;
import com.jxtc.enterprise.admin.vo.AdminAssignableCompanyVO;
import com.jxtc.enterprise.admin.vo.AdminAssignableStoreVO;
import com.jxtc.enterprise.admin.vo.TenantCreateVO;
import com.jxtc.enterprise.admin.vo.TenantVO;
import com.jxtc.enterprise.common.aspectj.TokenRequired;
import com.jxtc.enterprise.common.constants.TenantStatusEnum;
import com.jxtc.enterprise.common.entity.*;
import com.jxtc.enterprise.common.exception.ModifyFailureException;
import com.jxtc.enterprise.common.exception.UserAlreadyExistException;
import com.jxtc.enterprise.common.mapper.*;
import com.jxtc.enterprise.common.utils.Result;
import com.jxtc.enterprise.common.utils.ResultGenerator;
import com.jxtc.enterprise.common.vo.PaginationResponseVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 管理平台租户管理相关接口
 */

@RestController
@RequestMapping("/jxtc/enterprise/admin/tenantManage")
@RequiredArgsConstructor
@Slf4j
public class AdminTenantManagementController {

    private final TenantMapper tenantMapper;
    private final CompanyMapper companyMapper;

    private final AdminTenantStoreService adminTenantStoreService;
    private final StoreMapper storeMapper;
    private final FoodMapper foodMapper;
    private final OrderMapper orderMapper;
    private final TenantStoreMapper tenantStoreMapper;
    private final RedisTemplate<String, Object> redisTemplate;

    private final AdminTenantManageService adminTenantManageService;

    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 200 表示新增租户信息成功，data 字段为返回的公司信息")
    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示新增租户信息失败，message 字段则会提供错误信息")
    @Operation(summary = "1.7.1 管理员新增租户接口", tags = "1.7 管理员租户管理", operationId = "1.7.1")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @PostMapping("/addNewTenant")
    public Result<TenantCreateVO> addNewTenant(@Valid @RequestBody TenantCreateDTO dto) {
        log.info("/addNewTenant, request: {}", JSONObject.toJSONString(dto));

        Tenant tenant = new Tenant();
        tenant.setNickname(dto.getName());
        tenant.setPhone(dto.getPhone());
        // TODO: 当前密码未加密
        tenant.setPassword(dto.getPassword());
        tenant.setStatus(TenantStatusEnum.ACTIVE.getStatus());

        // 验证数据库中是否存在 phone 相同的用户，防止同一个手机号重复注册
        LambdaQueryWrapper<Tenant> queryWrapper = new LambdaQueryWrapper<Tenant>()
                .eq(Tenant::getPhone, dto.getPhone())
                .eq(Tenant::getDelFlag, false);
        // 手机号已经被注册时给前端返回提示信息
        if (tenantMapper.exists(queryWrapper)) {
            throw new UserAlreadyExistException("新增租户信息失败，该手机号已被占用");
        }

        // 手机号未被注册时，将数据保存到数据库中，并将租户 ID 返回给前端
        if (tenantMapper.insert(tenant) <= 0) {
            throw new ModifyFailureException("新增租户信息失败，请稍后重试");
        }

        TenantCreateVO vo = new TenantCreateVO();
        vo.setTenantId(tenant.getId());
        vo.setName(tenant.getNickname());

        log.info("/addNewTenant, response: {}", JSONObject.toJSONString(vo));
        return ResultGenerator.genSuccessResult(vo);
    }


    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示编辑租户信息失败，message 字段则会提供错误信息")
    @Operation(summary = "1.7.2 管理员编辑租户信息接口", tags = "1.7 管理员租户管理", operationId = "1.7.2")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @PostMapping("/editTenant")
    public Result<Void> editTenant(@Valid @RequestBody TenantUpdateDTO dto) {
        log.info("/editTenant, request: {}", JSONObject.toJSONString(dto));

        Tenant tenant = new Tenant();
        tenant.setId(dto.getTenantId());

        if (dto.getPhone() != null && !dto.getPhone().isEmpty()) {
            // 如果租户要修改手机号，需要判断该手机号是否已经被注册
            // 不允许修改为已经被注册的手机号
            LambdaQueryWrapper<Tenant> queryWrapper = new LambdaQueryWrapper<Tenant>()
                    .eq(Tenant::getPhone, dto.getPhone())
                    .eq(Tenant::getDelFlag, false);
            // 当租户表中，根据手机号查询得到的租户，不是当前入参中指定的租户A，则表示将入参中租户A的手机号修改为的新手机号，已经被占用了，不能改成被占用的号
            // 若手机号查询到的租户，就是入参中的租户A，则表示此接口调用时，没有修改手机号，修改的是其他信息，则抛出 手机号已被占用的异常，继续后面的逻辑
            // 若入参指定的手机号，租户表中查不到，则可以直接编辑
            Tenant tenantDetailVO = tenantMapper.selectOne(queryWrapper);
            if (tenantDetailVO != null && !tenantDetailVO.getId().equalsIgnoreCase(dto.getTenantId())) {
                throw new UserAlreadyExistException("编辑租户信息失败，该手机号已被占用");
            }

            // 如果手机号没有被占用，则可以正常被修改
            tenant.setPhone(dto.getPhone());
        }

        if (dto.getPassword() != null && !dto.getPassword().isEmpty()) {
            // TODO: 当前密码未加密
            tenant.setPassword(dto.getPassword());
        }

        if (dto.getAddress() != null && !dto.getAddress().isEmpty()) {
            tenant.setAddress(dto.getAddress());
        }

        if (dto.getNote() != null && !dto.getNote().isEmpty()) {
            tenant.setNote(dto.getNote());
        }

        int updateCount = tenantMapper.updateById(tenant);
        if (updateCount <= 0) {
            throw new ModifyFailureException("编辑租户信息失败，请稍后重试");
        }

        log.info("/editTenant, update count: {}", updateCount);
        return ResultGenerator.genSuccessResult();
    }


    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示启用/禁用租户失败，message 字段则会提供错误信息")
    @Operation(summary = "1.7.3 管理员启用/禁用租户接口", tags = "1.7 管理员租户管理", operationId = "1.7.3")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @PutMapping("/changeTenantState")
    public Result<Void> changeTenantState(@Valid @RequestBody TenantStateDTO dto) {
        log.info("/changeTenantState, request: {}", JSONObject.toJSONString(dto));

        Tenant tenant = new Tenant();
        tenant.setId(dto.getTenantId());

        if (TenantStatusEnum.ACTIVE.getStatus() == dto.getStatus()) {
            // 如果 status = 1
            tenant.setStatus(TenantStatusEnum.ACTIVE.getStatus());
        } else if (TenantStatusEnum.DEACTIVATE.getStatus() == dto.getStatus()) {
            // 如果 status = 2
            tenant.setStatus(TenantStatusEnum.DEACTIVATE.getStatus());
            // 禁用时，强制将租户退出登录，租户登录后在redis中会新增一个 key为租户id，value为 token的 数据项，每次调用租户接口时，
            // 都会先从token中解析出userId，获取到redis中的token，比对是否一致，验证token是否有效；因此，如果删除该 数据项，则后续的接口调用会失败，导致返回401
            redisTemplate.delete(dto.getTenantId());
        } else {
            // 其它状态码直接给前端抛出错误提示信息
            throw new IllegalArgumentException("启用或禁用租户失败，不存在该状态：" + dto.getStatus());
        }

        int updateCount = tenantMapper.updateById(tenant);
        if (updateCount <= 0) {
            throw new ModifyFailureException("修改租户状态失败，请稍后重试");
        }

        log.info("/changeTenantState, update count: {}", updateCount);
        return ResultGenerator.genSuccessResult();
    }


    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示删除租户失败，message 字段则会提供错误信息")
    @Parameter(name = "tenantId", description = "租户 ID", example = "c752804d0cd410267f404dd3f0457a57")
    @Operation(summary = "1.7.4 管理员删除租户接口", tags = "1.7 管理员租户管理", operationId = "1.7.4")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @DeleteMapping("/deleteTenant")
    public Result<Void> deleteTenantById(@RequestParam(value = "tenantId") String tenantId) {
        log.info("/deleteTenant, tenantId: {}", tenantId);

        Tenant tenant = new Tenant();
        tenant.setId(tenantId);
        tenant.setDelFlag(true);

        int updateCount = tenantMapper.updateById(tenant);
        if (updateCount <= 0) {
            throw new ModifyFailureException("删除租户失败，请稍后重试");
        }

        log.info("/deleteTenant, update count: {}", updateCount);
        return ResultGenerator.genSuccessResult();
    }


    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示查询租户信息失败，message 字段则会提供错误信息")
    @Parameter(name = "tenantId", description = "租户 ID", example = "c752804d0cd410267f404dd3f0457a57")
    @Operation(summary = "1.7.5 管理员根据租户 ID 查询租户信息接口", tags = "1.7 管理员租户管理", operationId = "1.7.5")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @GetMapping("/queryTenantById")
    public Result<TenantVO> queryTenantById(@RequestParam("tenantId") String tenantId) {
        log.info("/queryTenantById, tenantId: {}", tenantId);

        Tenant tenant = tenantMapper.selectById(tenantId);
        if (tenant == null) {
            throw new IllegalArgumentException("ID 为 " + tenantId + " 的租客不存在");
        }

        LambdaQueryWrapper<Company> companyQueryWrapper = new LambdaQueryWrapper<Company>()
                .eq(Company::getDelFlag, false)
                .eq(Company::getTenantId, tenantId)
                .select(Company::getId);
        List<String> companyIds = companyMapper.selectObjs(companyQueryWrapper);
        int companyCount = companyIds.size();

        LambdaQueryWrapper<Store> storeQueryWrapper = new LambdaQueryWrapper<Store>()
                .eq(Store::getDelFlag, false)
                .eq(Store::getTenantId, tenantId)
                .select(Store::getId);
        List<String> storeIds = storeMapper.selectObjs(storeQueryWrapper);
        int storeCount = storeIds.size();

        int foodCount = 0;
        if (!storeIds.isEmpty()) {
            LambdaQueryWrapper<Food> foodQueryWrapper = new LambdaQueryWrapper<Food>()
                    .eq(Food::getDelFlag, false)
                    .in(Food::getStoreId, storeIds);
            Long foodCountTemp = foodMapper.selectCount(foodQueryWrapper);
            foodCount = (foodCountTemp != null) ? foodCountTemp.intValue() : 0;
        }

        int orderCount = 0;
        if (!companyIds.isEmpty()) {
            LambdaQueryWrapper<OrderPayment> orderPaymentQueryWrapper = new LambdaQueryWrapper<OrderPayment>()
                    .in(OrderPayment::getCompanyId, companyIds);
            Long orderCountTemp = orderMapper.selectCount(orderPaymentQueryWrapper);
            orderCount = (orderCountTemp != null) ? orderCountTemp.intValue() : 0;
        }


        TenantVO tenantVO = buildTenantVO(tenant);
        tenantVO.setCompanyCount(companyCount);
        tenantVO.setStoreCount(storeCount);
        tenantVO.setFoodCount(foodCount);
        tenantVO.setOrderCount(orderCount);

        log.info("/queryTenantById, response: {}", JSONObject.toJSONString(tenantVO));
        return ResultGenerator.genSuccessResult(tenantVO);
    }


    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示查询租户信息失败，message 字段则会提供错误信息")
    @Parameter(name = "pageSize", description = "每页显示的记录数，默认为 20")
    @Parameter(name = "pageNo", description = "当前页码，从 1（默认值）开始")
    @Parameter(name = "searchKey", description = "根据租户名模糊查询关键字", example = "张")
    @Operation(summary = "1.7.6 管理员分页查询租户信息列表接口", tags = "1.7 管理员租户管理", operationId = "1.7.6")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @GetMapping("/queryAllTenant")
    public Result<PaginationResponseVO<TenantVO>> queryAllTenant(@RequestParam(value = "searchKey", required = false) String searchKey,
                                                                 @RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
                                                                 @RequestParam(value = "pageSize", required = false, defaultValue = "20") Integer pageSize) {
        log.info("/queryAllTenant, searchKey: {}, pageNo: {}, pageSize: {}", searchKey, pageNo, pageSize);

        Page<AdminTenantStatisticDTO> page = new Page<>(pageNo, pageSize);

        LambdaQueryWrapper<Tenant> queryWrapper = new LambdaQueryWrapper<Tenant>()
                .eq(Tenant::getDelFlag, false);

        if (searchKey != null && !searchKey.isEmpty()) {
            queryWrapper.like(Tenant::getNickname, searchKey);
        }

        Page<AdminTenantStatisticDTO> result = tenantMapper.pageTenantWithStatisticInfo(page, searchKey);
        List<TenantVO> records = result.getRecords().stream()
                .map(TenantVO::new)
                .collect(Collectors.toList());

        PaginationResponseVO<TenantVO> vo = new PaginationResponseVO<>(result.getTotal(), result.getCurrent(), records);

        log.info("/queryAllTenant, response: {}", JSONObject.toJSONString(vo));
        return ResultGenerator.genSuccessResult(vo);
    }

    private TenantVO buildTenantVO(Tenant tenant) {
        TenantVO vo = new TenantVO();
        vo.setTenantId(tenant.getId());
        vo.setName(tenant.getNickname());
        vo.setPhone(tenant.getPhone());
        vo.setAddress(tenant.getAddress());
        vo.setNote(tenant.getNote());

        vo.setPassword(tenant.getPassword());
        vo.setStatus(tenant.getStatus());
        return vo;
    }


    @ApiResponse(responseCode = "200", description = "code 为 200 时，data 字段为包含可以分配给其他租户的公司列表的分页信息")
    @Parameter(name = "pageSize", description = "每页显示的记录数，默认为 10")
    @Parameter(name = "pageNo", description = "当前页码，从 1（默认值）开始")
    @Parameter(name = "companyKeyword", description = "公司搜索关键字，公司名称、HR 名称或公司地址，支持模糊查询")
    @Parameter(name = "tenantName", description = "租户名（可选参数），不传递表示查询所有租户负责的公司")
    @Parameter(name = "targetTenantId", description = "目标租户 ID（必传字段），用于排除目标租户已有的公司")
    @Operation(summary = "1.7.7 查询可以分配给其他租户的公司列表", tags = "1.7 管理员租户管理", operationId = "1.7.7")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @GetMapping("/queryCanAssignableCompanies")
    public Result<PaginationResponseVO<AdminAssignableCompanyVO>> queryCanAssignableCompanies(@RequestParam String targetTenantId,
                                                                                              @RequestParam(required = false) String tenantName,
                                                                                              @RequestParam(required = false) String companyKeyword,
                                                                                              @RequestParam(required = false, defaultValue = "1") int pageNo,
                                                                                              @RequestParam(required = false, defaultValue = "10") int pageSize) {
        log.info("/queryCanAssignableCompanies, targetTenantId: {}, tenantName: {}, companyKeyword: {}, pageNo: {}, pageSize: {}", targetTenantId, tenantName, companyKeyword, pageNo, pageSize);

        // 校验目标租户是否存在，不存在时给出提示信息
        LambdaQueryWrapper<Tenant> queryWrapper = new LambdaQueryWrapper<Tenant>()
                .eq(Tenant::getId, targetTenantId);
        if (!tenantMapper.exists(queryWrapper)) {
            throw new IllegalArgumentException("ID 为 " + targetTenantId + " 的租户不存在，请联系管理员排查");
        }

        // 构造分页对象
        Page<CompanyWithTenantDTO> page = new Page<>(pageNo, pageSize);

        // 根据关键字和租户名模糊查询可以分配给其他租户的公司列表，并排除目标租户已有的公司
        Page<CompanyWithTenantDTO> result = companyMapper.queryCompanyByKeywordAndTenantName(page, companyKeyword, tenantName, targetTenantId);
        List<AdminAssignableCompanyVO> records = result.getRecords().stream()
                .map(AdminAssignableCompanyVO::new)
                .collect(Collectors.toList());

        PaginationResponseVO<AdminAssignableCompanyVO> vo = new PaginationResponseVO<>(result.getTotal(), result.getCurrent(), records);

        log.info("/queryCanAssignableCompanies, response: {}", JSONObject.toJSONString(vo));
        return ResultGenerator.genSuccessResult(vo);
    }


    @ApiResponse(responseCode = "200", description = "code 为 400 时，message 字段为错误提示信息")
    @Operation(summary = "1.7.8 为租户分配公司", tags = "1.7 管理员租户管理", operationId = "1.7.8")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @PostMapping("/assignCompaniesToTenant")
    public Result<Void> assignCompaniesToTenant(@Valid @RequestBody AssignCompaniesToTenantDTO dto) {
        log.info("/assignCompaniesToTenant, request: {}", JSONObject.toJSONString(dto));
        adminTenantManageService.assignCompaniesToTenant(dto.getTenantId(), dto.getCompanyIds());
        return ResultGenerator.genSuccessResult();
    }


    @ApiResponse(responseCode = "200", description = "code 为 200 时，data 字段为包含可以分配给指定租户的店铺列表的分页信息")
    @Parameter(name = "pageSize", description = "每页显示的记录数，默认为 10")
    @Parameter(name = "pageNo", description = "当前页码，从 1（默认值）开始")
    @Parameter(name = "storeKeyword", description = "店铺查询关键字，可以是店铺名、店主名或店铺地址")
    @Parameter(name = "targetTenantId", description = "目标租户 ID（必传字段），用于排除目标租户已绑定的店铺")
    @Operation(summary = "1.7.9 查询可以分配给指定租户的店铺列表", tags = "1.7 管理员租户管理", operationId = "1.7.9")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @GetMapping("/queryCanAssignableStores")
    public Result<PaginationResponseVO<AdminAssignableStoreVO>> queryCanAssignableStores(@RequestParam String targetTenantId,
                                                                                         @RequestParam(required = false) String storeKeyword,
                                                                                         @RequestParam(required = false, defaultValue = "1") int pageNo,
                                                                                         @RequestParam(required = false, defaultValue = "10") int pageSize) {
        log.info("/queryCanAssignableStores, targetTenantId: {}, storeKeyword: {}, pageNo: {}, pageSize: {}", targetTenantId, storeKeyword, pageNo, pageSize);

        // 校验目标租户是否存在，不存在时给出提示信息
        LambdaQueryWrapper<Tenant> queryWrapper = new LambdaQueryWrapper<Tenant>()
                .eq(Tenant::getId, targetTenantId);
        if (!tenantMapper.exists(queryWrapper)) {
            throw new IllegalArgumentException("ID 为 " + targetTenantId + " 的租户不存在，请联系管理员排查");
        }

        // 分页查询可分配的店铺列表
        PaginationResponseVO<AdminAssignableStoreVO> vo = adminTenantStoreService.queryCanAssignableStores(pageNo, pageSize, storeKeyword, targetTenantId);

        log.info("/queryCanAssignableStores, response: {}", JSONObject.toJSONString(vo));
        return ResultGenerator.genSuccessResult(vo);
    }


    @ApiResponse(responseCode = "200", description = "code 为 400 时，message 字段为错误提示信息")
    @Operation(summary = "1.7.10 为租户分配店铺", tags = "1.7 管理员租户管理", operationId = "1.7.10")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @PostMapping("/assignStoresToTenant")
    public Result<Void> assignStoresToTenant(@Valid @RequestBody AssignStoresToTenantDTO dto) {
        log.info("/assignStoresToTenant, request: {}", JSONObject.toJSONString(dto));

        // 校验目标租户是否存在，不存在时给出提示信息
        LambdaQueryWrapper<Tenant> queryWrapper = new LambdaQueryWrapper<Tenant>()
                .eq(Tenant::getId, dto.getTenantId());
        if (!tenantMapper.exists(queryWrapper)) {
            throw new IllegalArgumentException("ID 为 " + dto.getTenantId() + " 的租户不存在，请联系管理员排查");
        }

        // 批量保存，失败时给出错误信息并回滚事务
        adminTenantStoreService.assignStoresToTenant(dto.getStoreIds(), dto.getTenantId());

        log.info("/assignStoresToTenant, assign {} stores to tenant: {} successfully", dto.getStoreIds().size(), dto.getTenantId());
        return ResultGenerator.genSuccessResult();
    }

    @ApiResponse(responseCode = "200", description = "code 为 400 时，message 字段为错误提示信息")
    @Operation(summary = "1.7.11 查询授权给租户的店铺列表(仅返回授权的店铺，不返回租户直属的店铺)", tags = "1.7 管理员租户管理", operationId = "1.7.11")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @GetMapping("/queryAuthorizedStores")
    public Result<Page<TenantRelatedStoreDTO>> queryAuthorizedStores(@RequestParam(name = "tenantId") String tenantId,
                                                 @RequestParam(name = "pageNo") Integer pageNo,
                                                 @RequestParam(name = "pageSize") Integer pageSize) {
        log.info("/queryAuthorizedStores, tenantId: {}", tenantId);

        // 构造分页对象
        Page<TenantRelatedStoreDTO> page = new Page<>(pageNo, pageSize);
        Page<TenantRelatedStoreDTO> vo = storeMapper.queryAuthorizedStores(page, tenantId);

        log.info("/queryAuthorizedStores, response: {}", JSONObject.toJSONString(vo));
        return ResultGenerator.genSuccessResult(vo);
    }


    @ApiResponse(responseCode = "200", description = "code 为 400 时，message 字段为错误提示信息")
    @Operation(summary = "1.7.12 解除某个店铺的授权关系", tags = "1.7 管理员租户管理", operationId = "1.7.12")
    @TokenRequired(role = TokenRequired.ROLE_ADMIN)
    @GetMapping("/cancelAuthorizationOfStoreForTenant")
    public Result<Void> cancelAuthorizationOfStoreForTenant(@RequestParam(name = "tenantId") String tenantId,
                                                                        @RequestParam(name = "storeId") String storeId) {
        log.info("/cancelAuthorizationOfStoreForTenant, tenantId: {}, storeId: {}", tenantId, storeId);

        int canceledStoreCount = tenantStoreMapper.update(
                new LambdaUpdateWrapper<TenantStore>()
                        .eq(TenantStore::getTenantId,tenantId)
                        .eq(TenantStore::getStoreId, storeId)
                        .set(TenantStore::getDelFlag, true)
                        .set(TenantStore::getUpdateTime, LocalDateTime.now()));

        log.info("/cancelAuthorizationOfStoreForTenant, canceled {} stored successfully", canceledStoreCount);
        return ResultGenerator.genSuccessResult();
    }
}
